﻿using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization;

namespace Devonline.Identity;

/// <summary>
/// 多语言支持的默认身份相关错误描述
/// </summary>
public class DefaultIdentityErrorDescriber(IStringLocalizer<DefaultIdentityErrorDescriber> localizer) : IdentityErrorDescriber
{
    private readonly IStringLocalizer<DefaultIdentityErrorDescriber> _localizer = localizer;

    #region 按默认的 Identity Error Code 返回 IdentityError 对象的基础方法
    /// <summary>
    /// 按默认的 Identity Error Code 返回 IdentityError 对象
    /// </summary>
    /// <param name="code">错误代码</param>
    /// <returns></returns>
    public virtual IdentityError GetIdentityError(string code)
    {
        return new IdentityError
        {
            Code = code,
            Description = _localizer[code]
        };
    }
    /// <summary>
    /// 按默认的 Identity Error Code 返回 IdentityError 对象
    /// </summary>
    /// <param name="code">错误代码</param>
    /// <param name="args">参数列表</param>
    /// <returns></returns>
    public virtual IdentityError GetIdentityError(string code, params object[] args)
    {
        return new IdentityError
        {
            Code = code,
            Description = _localizer[code, args]
        };
    }
    #endregion

    #region 重载的积累方法
    /// <summary>
    /// Returns the default <see cref="IdentityError"/>.
    /// </summary>
    /// <returns>The default <see cref="IdentityError"/>.</returns>
    public override IdentityError DefaultError() => GetIdentityError(nameof(DefaultError));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a concurrency failure.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a concurrency failure.</returns>
    public override IdentityError ConcurrencyFailure() => GetIdentityError(nameof(ConcurrencyFailure));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a password mismatch.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a password mismatch.</returns>
    public override IdentityError PasswordMismatch() => GetIdentityError(nameof(PasswordMismatch));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating an invalid token.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating an invalid token.</returns>
    public override IdentityError InvalidToken() => GetIdentityError(nameof(InvalidToken));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a recovery code was not redeemed.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a recovery code was not redeemed.</returns>
    public override IdentityError RecoveryCodeRedemptionFailed() => GetIdentityError(nameof(RecoveryCodeRedemptionFailed));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating an external login is already associated with an account.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating an external login is already associated with an account.</returns>
    public override IdentityError LoginAlreadyAssociated() => GetIdentityError(nameof(LoginAlreadyAssociated));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating the specified user <paramref name="userName"/> is invalid.
    /// </summary>
    /// <param name="userName">The user name that is invalid.</param>
    /// <returns>An <see cref="IdentityError"/> indicating the specified user <paramref name="userName"/> is invalid.</returns>
    public override IdentityError InvalidUserName(string? userName) => GetIdentityError(nameof(InvalidUserName), userName ?? throw new ArgumentNullException(nameof(userName)));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating the specified <paramref name="email"/> is invalid.
    /// </summary>
    /// <param name="email">The email that is invalid.</param>
    /// <returns>An <see cref="IdentityError"/> indicating the specified <paramref name="email"/> is invalid.</returns>
    public override IdentityError InvalidEmail(string? email) => GetIdentityError(nameof(InvalidEmail), email ?? throw new ArgumentNullException(nameof(email)));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating the specified <paramref name="userName"/> already exists.
    /// </summary>
    /// <param name="userName">The user name that already exists.</param>
    /// <returns>An <see cref="IdentityError"/> indicating the specified <paramref name="userName"/> already exists.</returns>
    public override IdentityError DuplicateUserName(string userName) => GetIdentityError(nameof(DuplicateUserName), userName ?? throw new ArgumentNullException(nameof(userName)));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating the specified <paramref name="email"/> is already associated with an account.
    /// </summary>
    /// <param name="email">The email that is already associated with an account.</param>
    /// <returns>An <see cref="IdentityError"/> indicating the specified <paramref name="email"/> is already associated with an account.</returns>
    public override IdentityError DuplicateEmail(string email) => GetIdentityError(nameof(DuplicateEmail), email);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating the specified <paramref name="role"/> name is invalid.
    /// </summary>
    /// <param name="role">The invalid role.</param>
    /// <returns>An <see cref="IdentityError"/> indicating the specific role <paramref name="role"/> name is invalid.</returns>
    public override IdentityError InvalidRoleName(string? role) => GetIdentityError(nameof(InvalidRoleName), role ?? throw new ArgumentNullException(nameof(role)));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating the specified <paramref name="role"/> name already exists.
    /// </summary>
    /// <param name="role">The duplicate role.</param>
    /// <returns>An <see cref="IdentityError"/> indicating the specific role <paramref name="role"/> name already exists.</returns>
    public override IdentityError DuplicateRoleName(string role) => GetIdentityError(nameof(DuplicateRoleName), role);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a user already has a password.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a user already has a password.</returns>
    public override IdentityError UserAlreadyHasPassword() => GetIdentityError(nameof(UserAlreadyHasPassword));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating user lockout is not enabled.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating user lockout is not enabled.</returns>
    public override IdentityError UserLockoutNotEnabled() => GetIdentityError(nameof(UserLockoutNotEnabled));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a user is already in the specified <paramref name="role"/>.
    /// </summary>
    /// <param name="role">The duplicate role.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a user is already in the specified <paramref name="role"/>.</returns>
    public override IdentityError UserAlreadyInRole(string role) => GetIdentityError(nameof(UserAlreadyInRole), role);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a user is not in the specified <paramref name="role"/>.
    /// </summary>
    /// <param name="role">The duplicate role.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a user is not in the specified <paramref name="role"/>.</returns>
    public override IdentityError UserNotInRole(string role) => GetIdentityError(nameof(UserNotInRole), role);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a password of the specified <paramref name="length"/> does not meet the minimum length requirements.
    /// </summary>
    /// <param name="length">The length that is not long enough.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a password of the specified <paramref name="length"/> does not meet the minimum length requirements.</returns>
    public override IdentityError PasswordTooShort(int length) => GetIdentityError(nameof(PasswordTooShort), length);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a password does not meet the minimum number <paramref name="uniqueChars"/> of unique chars.
    /// </summary>
    /// <param name="uniqueChars">The number of different chars that must be used.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a password does not meet the minimum number <paramref name="uniqueChars"/> of unique chars.</returns>
    public override IdentityError PasswordRequiresUniqueChars(int uniqueChars) => GetIdentityError(nameof(PasswordRequiresUniqueChars), uniqueChars);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a password entered does not contain a non-alphanumeric character, which is required by the password policy.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a password entered does not contain a non-alphanumeric character.</returns>
    public override IdentityError PasswordRequiresNonAlphanumeric() => GetIdentityError(nameof(PasswordRequiresNonAlphanumeric));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a password entered does not contain a numeric character, which is required by the password policy.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a password entered does not contain a numeric character.</returns>
    public override IdentityError PasswordRequiresDigit() => GetIdentityError(nameof(PasswordRequiresDigit));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a password entered does not contain a lower case letter, which is required by the password policy.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a password entered does not contain a lower case letter.</returns>
    public override IdentityError PasswordRequiresLower() => GetIdentityError(nameof(PasswordRequiresLower));
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a password entered does not contain an upper case letter, which is required by the password policy.
    /// </summary>
    /// <returns>An <see cref="IdentityError"/> indicating a password entered does not contain an upper case letter.</returns>
    public override IdentityError PasswordRequiresUpper() => GetIdentityError(nameof(PasswordRequiresUpper));
    #endregion

    #region 自定义部分
    /// <summary>
    /// Returns the default <see cref="IdentityError"/>.
    /// </summary>
    /// <returns>The default <see cref="IdentityError"/>.</returns>
    public virtual IdentityError ChangeFailure(string type, string value) => GetIdentityError(nameof(ChangeFailure), type, value);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating the specified <paramref name="group"/> name is invalid.
    /// </summary>
    /// <param name="group">The invalid role.</param>
    /// <returns>An <see cref="IdentityError"/> indicating the specific group <paramref name="group"/> name is invalid.</returns>
    public virtual IdentityError InvalidGroupName(string group) => GetIdentityError(nameof(InvalidGroupName), group);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a user is already in the specified <paramref name="group"/>.
    /// </summary>
    /// <param name="user">The duplicate user.</param>
    /// <param name="group">The duplicate group.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a user is already in the specified <paramref name="group"/>.</returns>
    public virtual IdentityError UserAlreadyInGroup(string user, string group) => GetIdentityError(nameof(UserAlreadyInGroup), user, group);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a user is not in the specified <paramref name="group"/>.
    /// </summary>
    /// <param name="user">The duplicate user.</param>
    /// <param name="group">The duplicate group.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a user is not in the specified <paramref name="group"/>.</returns>
    public virtual IdentityError UserNotInGroup(string user, string group) => GetIdentityError(nameof(UserNotInGroup), user, group);

    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a user is already in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="user">The duplicate user.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a user is already in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError UserAlreadyInAccessRule(string user, string resource) => GetIdentityError(nameof(UserAlreadyInAccessRule), user, resource);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a role is already in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="role">The duplicate role.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a role is already in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError RoleAlreadyInAccessRule(string role, string resource) => GetIdentityError(nameof(RoleAlreadyInAccessRule), role, resource);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a group is already in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="group">The duplicate group.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a group is already in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError GroupAlreadyInAccessRule(string group, string resource) => GetIdentityError(nameof(GroupAlreadyInAccessRule), group, resource);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a group is already in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="level">The duplicate group.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a group is already in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError LevelAlreadyInAccessRule(string level, string resource) => GetIdentityError(nameof(LevelAlreadyInAccessRule), level, resource);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a user is not in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="user">The duplicate user.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a user is not in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError UserNotInAccessRule(string user, string resource) => GetIdentityError(nameof(UserNotInAccessRule), user, resource);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a role is not in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="role">The duplicate role.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a role is not in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError RoleNotInAccessRule(string role, string resource) => GetIdentityError(nameof(RoleNotInAccessRule), role, resource);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a group is not in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="group">The duplicate group.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a group is not in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError GroupNotInAccessRule(string group, string resource) => GetIdentityError(nameof(GroupNotInAccessRule), group, resource);
    /// <summary>
    /// Returns an <see cref="IdentityError"/> indicating a group is not in the specified <paramref name="resource"/>.
    /// </summary>
    /// <param name="level">The duplicate group.</param>
    /// <param name="resource">The duplicate resource.</param>
    /// <returns>An <see cref="IdentityError"/> indicating a group is not in the specified <paramref name="resource"/>.</returns>
    public virtual IdentityError LevelNotInAccessRule(string level, string resource) => GetIdentityError(nameof(LevelNotInAccessRule), level, resource);
    #endregion
}
